#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##-- G03 -- S03 ------------------------------------------------------------##
__all__ = []

from .. import comparecards as cmp_cards
from .. import formlib as layout
from .. import pilelib as stack
from .. import stackfill as fill
from ..gamelib import info as gi, state, game
from ..hint import CautiousDefaultHint
from ..packlib import info as cs, place

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class Foundation(stack.SS_Foundation):
    """
    Build up around in rank by same suit.
    """

    def _sequence(self, cards):
        """
        _sequence(cards:seq) -> bool

        Sequence builds to highest rank, matches and builds back to lowest.

        :param sequence cards: cards from sending pile
        :return: accept card sequence acccording to *capabilities*?
        :rtype: boolean
        """
        ranks = self.game['ranks']  # assume ranks are ordered
        hr = len(ranks) - 1  # last rank is paired not built
        l = len(self.cards)
        card_rank = ranks.index(cards[0]['rank'])
        return ((l > hr and card_rank == hr * 2 + 1 - l) or card_rank == l)


class SS_RowStack(stack.SS_RowStack):
    """
    Build in rank by same suit. Dir set by 2nd card on pile. _BOTTOM_IMAGE_ is
    shade.
    """
    _BOTTOM_IMAGE_ = 'shade'

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:seq) -> bool

        Check parent.acceptsCard() acccording to *capabilities*. Before 2nd
        card set cap['dir'] for pile.

        :param object from_stack: sending pile
        :param sequence cards: cards from sending pile
        :return: pile accepts ``cards``?
        :rtype: boolean
        """
        if len(self.cards) == 1:
            dir_ = cmp_cards.getDirection(self.cards[-1:] + cards)
            if dir_ in [1, -1]:
                self.game._save_stack_caps(self, dir=dir_)
            else:
                return False
        return super(SS_RowStack, self).cardsBuild(from_stack, cards)


class UnionSquare(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 16 over 4 row. Init deal 1 card. Build next in rank by same suit.
      Play top.

    _talon_
      Pile 1 NW. Deal _waste_ 1 card.

    _waste_
      Pile 1 E of _talon_. Init deal 1 card. Build none. Play top.

    _foundation_
      Pile 4 vert E. Build up around in rank by same suit. No card play.

    note::
      ⟪highlight_play⟫ disabled.
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=1)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: Foundation (max_cards=26,
      max_move=0, dir=0)
    :cvar Stack _row_: SS_RowStack (dir=0, max_accept=1, max_move=1)
    :cvar Hint _hint_: hint.CautiousDefaultHint
    """
    __info__ = dict(id=35, name='Union Square', game_type=(GT.TWO_DECK |
                    GT.GNOME), decks=2, skill_level=SL.MOSTLY_SKILL,
                    altnames=('British Square',), version='2.90',)
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = Wrap(stack.WasteTalon, max_rounds=1)
    _waste_ = stack.WasteStack
    _foundation_ = Wrap(Foundation, max_cards=26, max_move=0, dir=0)
    _row_ = Wrap(SS_RowStack, dir=0, max_accept=1, max_move=1)
    _hint_ = CautiousDefaultHint

    def _create_game(self, rows=16, **kw):
        l, s = layout.Layout(self), self.s  # card_y_space=20)
        self.table_size = (l.XM + (5 + rows / 4) * l.XS, l.YM + 4 * l.YS)
        x, y, = l.XM, l.YM
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 's')
        x += l.XS
        s['wastes'].append(self._waste_(x, y, game=self))
        l.set_ncards_text(s['wastes'][-1], 's')
        for i in range(4):
            x = 3 * l.XS
            for j in range(rows / 4):
                s['rows'].append(self._row_(x, y, self, offset=(0, 3)))
                x += l.XS
            y += l.YS
        x, y = self.width - l.XS, l.YM
        for i in l.SUIT:
            s['foundations'].append(self._foundation_(x, y, game=self, suit=i))
            l.set_ncards_text(s['foundations'][i], 'sw')
            y += l.YS
        l.defaultStackGroups()
        return l

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1 ea.

        .. \_start([]) -> None
        """
        self.s['talon'].dealRow()

    @property
    def _highlight_piles(self):
        """
        Get stacks to highlight for possible move.

        :return: empty.
        :rtype: tuple
        """
        return ()


class Boomerang(UnionSquare):
    """
    Finish cards on _foundation_ within a turn.
    _row_
      Pile 12 over 4 row. Init deal 1 card. Build next in rank by same suit.
      Play top. Gap deal 1 card from _waste_.

    _talon_
      Pile 1 NW. Deal _waste_ 1 card.

    _waste_
      Pile 1 E of _talon_. Init deal 1 card. Build none. Play top.

    _foundation_
      Pile 4 vert E. Build up around in rank by same suit. No card play.

    note::
      ⟪highlight_play⟫ disabled.
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=1)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: Foundation (max_cards=16,
      base_rank=SEVEN, max_move=0, dir=0)
    :cvar Stack _row_: SS_RowStack (base_rank=GAP)
    :cvar Hint _hint_: hint.CautiousDefaultHint
    """
    __info__ = dict(id=738, name='Boomerang', game_type=GT.TWO_DECK, decks=2,
                    skill_level=SL.BALANCED, ranks=cs.SHORT_A7K,
                    version='1.10fc')
    __author__ = 'Skomoroh'
    __credits__ = ['Albert Morehead', 'Geoffrey Mott-Smith']
    __version__ = 7.70

    _foundation_ = Wrap(Foundation, base_rank=cs.SEVEN, max_cards=16,
                        max_move=0, dir=0)
    _row_ = Wrap(SS_RowStack, base_rank=cs.GAP)

    def _create_game(self, **kw):
        kw.setdefault('rows', 12)
        return super(Boomerang, self)._create_game(**kw)

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Fill stack if _row_ when gap from _waste_.

        *Parameters*:
          stack : Stack
            pile just played
        """
        fill.fromWaste(self, stack, self.s['rows'])


class SolidSquare(Boomerang):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 20 over 4 row. Init deal 1 card. Build either in rank by same suit.
      Play top. Gap deal 1 card from _waste_.

    _talon_
      Pile 1 NW. Deal _waste_ 1 card.

    _waste_
      Pile 1 E of _talon_. Init deal 1 card. Build none. Play top.

    _foundation_
      Pile 4 vert E. Build up around in rank by same suit. No card play.

    note::
      ⟪highlight_play⟫ disabled.
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=1)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: Foundation (max_cards=26,
      max_move=0, dir=0)
    :cvar Stack _row_: stack.UD_SS_RowStack (base_rank=GAP, mod=13
    :cvar Hint _hint_: hint.CautiousDefaultHint
    """
    __info__ = dict(id=439, name='Solid Square', game_type=GT.TWO_DECK,
                    decks=2, skill_level=SL.BALANCED,
                    version='0.91fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundation_ = Wrap(Foundation, max_cards=26, max_move=0, dir=0)
    _row_ = Wrap(stack.UD_SS_RowStack, base_rank=cs.GAP, mod=13)

    def _create_game(self, **kw):
        kw.setdefault('rows', 20)
        return super(SolidSquare, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return ACE of suit on top by suit for _foundation_ deal.
        """
        return place.MoveToTop(cards, place.OneAce)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[foundations] 1 ea.
          - s[rows] 1 ea.

        .. \_start([]) -> None
        """
        self.s['talon'].dealRow(rows=self.s['foundations'], frames=0)
        super(SolidSquare, self)._start(**kw)


PROVIDES = [UnionSquare, SolidSquare, Boomerang]